#
# if you want the ram-disk device, define this to be the
# size in blocks.
#
RAMDISK = #-DRAMDISK=512

# 8086汇编编译器和链接器
# -0表示生成8086目标程序，-a生成与gas和gld部分兼容的代码
AS86	=as86 -0 -a
LD86	=ld86 -0

# GNU汇编编译器和链接器
AS	=gas
LD	=gld
# -s 输出文件中省略所有的符号信息
# -x 删除所有局部符号
# -M 表示需要在标准输出设备上打印连接映像（link map），
#    是指由连接程序产生的一种内存地址映像，其中列出了程
#    序段装入到内存中的位置信息。具体来讲有如下信息：
#    1.目标文件及符号信息映射到内存中的位置
#    2.公共符号如何放置
#    3.连接中包含的所有文件成员及其引用的符号
LDFLAGS	=-s -x -M

CC	=gcc $(RAMDISK)
# -Wall 打印所有的警告信息
# -0 对代码进行优化
# -fstrength-reduce 优化循环语句
# -mstring-insns 用于在复制结构等操作时使用386CPU的字符串指令，可以去掉
CFLAGS	=-Wall -O -fstrength-reduce -fomit-frame-pointer \
-fcombine-regs -mstring-insns
# cpp是gcc的与处理程序
# -nostdinc -Iinclude指不要搜索标准的头文件目录中的文件，
# 而是使用-I选项指定的目录或者是在当前目录里面搜索头文件
CPP	=cpp -nostdinc -Iinclude

#
# ROOT_DEV specifies the default root-device when making the image.
# This can be either FLOPPY, /dev/xxxx or empty, in which case the
# default of /dev/hd6 is used by 'build'.
#
ROOT_DEV=/dev/hd6

# kernel目录、mm目录和fs目录所产生的目标代码文件
ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o
# 块和字符设备文件
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
# 数学运算库文件
MATH	=kernel/math/math.a
# 有lib/目录中的文件所编译生成的通用库文件
LIBS	=lib/lib.a

# 将所有的.c文件编译生成.s汇编文件
.c.s:
	$(CC) $(CFLAGS) \
	-nostdinc -Iinclude -S -o $*.s $<

# 将所有的.s汇编程序编译成.o目标文件
.s.o:
	$(AS) -c -o $*.o $<

# 将.c文件编译成.o目标文件
.c.o:
	$(CC) $(CFLAGS) \
	-nostdinc -Iinclude -c -o $*.o $<

all:	Image # all创建Makefile所知的最顶层的目标

# 说明Image是由后面的四个元素产生
Image: boot/bootsect boot/setup tools/system tools/build
	tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image
	# 迫使缓冲块数据立即写盘并更新超级块
	sync

# 表示disk目标要由Image产生
disk: Image
	dd bs=8192 if=Image of=/dev/PS0

# 由tools目录下的build.c程序生成执行程序build
tools/build: tools/build.c
	$(CC) $(CFLAGS) \
	-o tools/build tools/build.c

# 利用上面给出的.s .o规则生成head.o
boot/head.o: boot/head.s

# tool中的system文件由右侧所列元素生成
tools/system:	boot/head.o init/main.o \
		$(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS)
	$(LD) $(LDFLAGS) boot/head.o init/main.o \
	$(ARCHIVES) \
	$(DRIVERS) \
	$(MATH) \
	$(LIBS) \
	-o tools/system > System.map

# 数学协处理函数math.a
kernel/math/math.a:
	(cd kernel/math; make)
# 块设备函数文件blk_drv.a
kernel/blk_drv/blk_drv.a:
	(cd kernel/blk_drv; make)
# 字符设备函数文件chr_drv.a
kernel/chr_drv/chr_drv.a:
	(cd kernel/chr_drv; make)
# 内核目标模块kernel.o
kernel/kernel.o:
	(cd kernel; make)
# 内存管理模块mm.o
mm/mm.o:
	(cd mm; make)
# 文件系统目标木块fs.o
fs/fs.o:
	(cd fs; make)
# 库函数lib.a
lib/lib.a:
	(cd lib; make)
# 使用8086汇编和链接器对setup.s文件进行汇编生成setup文件
# -s 表示要去除目标文件中的符号信息
boot/setup: boot/setup.s
	$(AS86) -o boot/setup.o boot/setup.s
	$(LD86) -s -o boot/setup boot/setup.o
# 生成bootsect.o磁盘引导块
boot/bootsect:	boot/bootsect.s
	$(AS86) -o boot/bootsect.o boot/bootsect.s
	$(LD86) -s -o boot/bootsect boot/bootsect.o
# 在bootsect.s程序开头添加一行有关system文件长度信息。
# 方法是首先生成还有"SYSSIZE = system"文件实际长度一行信息的temp.s文件，
# 然后将bootsect.s文件添加在其后。
# 取得system长度的方法是：
# 首先利用命令ls对system文件进行长列表显示，用grep命令取得列表行
# 上文件字节数字段信息，并定向保存在temp.s临时文件中，cut命令用于
# 剪切字符串，tr用于去除行尾的回车符。
# 其中：（实际长度+15）/16用于获得用‘节’表示的长度信息。1节=16字节。
tmp.s:	boot/bootsect.s tools/system
	(echo -n "SYSSIZE = (";ls -l tools/system | grep system \
		| cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
	cat boot/bootsect.s >> tmp.s

clean:
	rm -f Image System.map tmp_make core boot/bootsect boot/setup
	rm -f init/*.o tools/system tools/build boot/*.o
	(cd mm;make clean)
	(cd fs;make clean)
	(cd kernel;make clean)
	(cd lib;make clean)

# 该规则将首先执行上面的clean规则，然后对linux/目录进行压缩，生成
# backuo.Z压缩文件。‘cd ..’表示推到linux/的上一级目录；
# 'tar cf - linux'表示对linux/目录执行tar归档，-cf表示创建新的归档
# 文件
# '| compress -'表示将tar程序的执行通过管道操作传递给压缩程序compress,
# 并将压缩程序的输出存成backup.Z文件。
backup: clean
	(cd .. ; tar cf - linux | compress - > backup.Z)
	# 迫使缓冲块数据立即写盘并更新超级块
	sync

# 该目标用于各文件之间的依赖关系。
dep:
	sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
	(for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make
	cp tmp_make Makefile
	(cd fs; make dep)
	(cd kernel; make dep)
	(cd mm; make dep)

### Dependencies:
init/main.o : init/main.c include/unistd.h include/sys/stat.h \
  include/sys/types.h include/sys/times.h include/sys/utsname.h \
  include/utime.h include/time.h include/linux/tty.h include/termios.h \
  include/linux/sched.h include/linux/head.h include/linux/fs.h \
  include/linux/mm.h include/signal.h include/asm/system.h include/asm/io.h \
  include/stddef.h include/stdarg.h include/fcntl.h 
